/*******************************************************************************
 * Copyright (c) 2011 EclipseDevX.org and others.
 * 
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License v1.0 which
 * accompanies this distribution, and is available at:
 * 
 *     http://www.eclipse.org/legal/epl-v10.html
 *******************************************************************************/

package org.eclipsedevx.metrics.ui;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.ViewPart;
import org.eclipsedevx.core.graphing.GraphControl;
import org.eclipsedevx.core.utils.SelectionUtils;
import org.eclipsedevx.metrics.DevXMetricsPlugin;
import org.eclipsedevx.metrics.model.MetricsData;
import org.eclipsedevx.metrics.model.MetricsHistory;

/**
 * 
 * 
 * @author dcarew
 */
public class MetricsView extends ViewPart implements ISelectionListener {
    private static String EMPTY_CHART = "http://chart.apis.google.com/chart?chxr=0,0,109&chxt=y&cht=lc&chco=3072F3&chds=0,109&chg=14.3,-1,1,1&chls=2,4,0";
    
	private GraphControl metricsGraph;
    
    private Label fileCountLabel;
    private Label slocCountLabel;
    private Label ccnCountLabel;
    
    private String currentSelectionToken = "";
    
	public MetricsView() {
		
	}

	public void createPartControl(Composite parent) {
	    Color color = parent.getDisplay().getSystemColor(SWT.COLOR_WHITE);
	    parent.setBackground(color);
	    
	    Composite composite = new Composite(parent, SWT.NONE);
	    composite.setBackground(color);
	    GridLayoutFactory.fillDefaults().margins(5, 5).numColumns(2).applyTo(composite);
	    
        // metricsGraph
        metricsGraph = new GraphControl(composite, SWT.NONE); //SWT.BORDER);
        GridDataFactory.fillDefaults().grab(true, true).applyTo(metricsGraph);
        
	    // text stats
	    Composite textStats = new Composite(composite, SWT.NONE);
	    textStats.setBackground(color);
        GridDataFactory.fillDefaults().grab(false, true).align(SWT.BEGINNING, SWT.CENTER).applyTo(textStats);
	    GridLayoutFactory.fillDefaults().numColumns(2).spacing(3, 0).applyTo(textStats);
	    
        fileCountLabel = createLabel(textStats, "files", null);
        slocCountLabel = createLabel(textStats, "SLOC", "Source lines of code");
        ccnCountLabel = createLabel(textStats, "CCN", "TODO:");
        
        Label spacer = createLabel(textStats, "", null);
        GridDataFactory.fillDefaults().hint(43, SWT.DEFAULT).applyTo(spacer);
        
	    metricsGraph.setGraphUrl(EMPTY_CHART);
	}

    @Override
    public void init(IViewSite site) throws PartInitException {
        super.init(site);
        
        site.getPage().addSelectionListener(this);
    }

	public void setFocus() {

	}

    public void selectionChanged(IWorkbenchPart part, ISelection selection) {
        List<IResource> resources = SelectionUtils.getObjects(selection, IResource.class);
        
        if (resources.size() == 0 && !(selection instanceof IStructuredSelection)) {
            IResource resource = SelectionUtils.getResourceFor(part);
            
            if (resource != null) {
                resources = Collections.singletonList(resource);
            }
        }
        
        updateSelection(resources);
    }

    @Override
    public void dispose() {
        getSite().getPage().removeSelectionListener(this);
        
        super.dispose();
    }

    private Label createLabel(Composite composite, String title, String tooltip) {
        Label label1 = new Label(composite, SWT.RIGHT);
        label1.setText("");
        label1.setBackground(composite.getBackground());
        GridDataFactory.fillDefaults().applyTo(label1);
        
        Label label2 = new Label(composite, SWT.NONE);
        label2.setText(title);
        label2.setBackground(composite.getBackground());
        GridDataFactory.fillDefaults().applyTo(label2);
        
        if (tooltip != null) {
            label1.setToolTipText(tooltip);
            label2.setToolTipText(tooltip);
        }
        
        return label1;
    }

    private void updateSelection(List<IResource> resources) {
    	String newSelectionToken = createSelectionToken(resources);
    	
    	if (!currentSelectionToken.equals(newSelectionToken)) {
    		currentSelectionToken = newSelectionToken;
    		
    		updateSelectionImpl(resources);
    	}
    }
    
	private void updateSelectionImpl(List<IResource> resources) {
        MetricsData metrics = null;
        List<IProject> projects = new ArrayList<IProject>();
        
        for (IResource resource : resources) {
            if (resource instanceof IProject) {
                projects.add((IProject)resource);
            }
            
            MetricsData m = DevXMetricsPlugin.getPlugin().getMetricsData(resource);
            
            if (m != null) {
                if (metrics == null) {
                    metrics = m;
                } else {
                    metrics.add(m);
                }
            }
        }
        
        if (metrics == null) {
            fileCountLabel.setText("");
            slocCountLabel.setText("");
            ccnCountLabel.setText("");
        } else {
            fileCountLabel.setText(format(metrics.getValue(MetricsData.JAVA_FILES)));
            slocCountLabel.setText(format(metrics.getValue(MetricsData.JAVA_SLOC)));
            ccnCountLabel.setText(format(metrics.getValue(MetricsData.JAVA_CNC)));
        }
        
        if (projects.size() == 0) {
            metricsGraph.setGraphUrl(EMPTY_CHART);
        } else {
            MetricsHistory history = DevXMetricsPlugin.getPlugin().getProjectHistory().
                getMetricsHistory(projects);
            
            if (history == null) {
                metricsGraph.setGraphUrl(EMPTY_CHART);
            } else {
            	metricsGraph.setGraphUrl(getGraphUrlFor(history));
            }
        }
        
        ccnCountLabel.getParent().getParent().layout();
    }
    
    private String createSelectionToken(List<IResource> resources) {
    	StringBuilder builder = new StringBuilder();
    	
    	for (IResource resource : resources) {
    		builder.append(resource.getProjectRelativePath().toPortableString() + "\n");
    	}
    	
		return builder.toString();
	}

    private String getGraphUrlFor(MetricsHistory history) {
        int graphMaxValue = history.getMaxVisualValue();
        
        List<Integer> values = history.getDayValues();
        
        StringBuilder builder = new StringBuilder();
        
        for (Integer i : values) {
            builder.append(i + ",");
        }
        
        if (builder.length() > 0) {
            builder.setLength(builder.length() - 1);
        }
        
        return "http://chart.apis.google.com/chart?chxr=0,0,"
            + graphMaxValue + "&chxt=y&cht=lc&chco=3072F3&chds=0," + graphMaxValue + "&chd=t:"
            + builder.toString()
            + "&chg=14.3,-1,1,1&chls=2,4,0";
    }

    private static NumberFormat intFormat = NumberFormat.getIntegerInstance();
    private static NumberFormat doubleFormat = NumberFormat.getNumberInstance();
    
    static {
        doubleFormat.setMinimumFractionDigits(2);  
        doubleFormat.setMaximumFractionDigits(2);  
    }
    
    private String format(String value) {
        if (value == null) {
            return intFormat.format(0);
        } else if (value.indexOf('.') != -1) {
            try {
                double val = Double.valueOf(value);
                
                return doubleFormat.format(val);
            } catch (NumberFormatException nfe) {
                return doubleFormat.format(0.0);
            }
        } else {
            try {
                int val = Integer.valueOf(value);
                
                return intFormat.format(val);
            } catch (NumberFormatException nfe) {
                return intFormat.format(0);
            }
        }
    }

}
